<?php

namespace App\Console\Commands;

use App\Models\Cdr;
use App\Models\Gateway;
use App\Models\Sip;
use App\Service\SwooleFreeswitch;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use App\Service\EslListen;

class SwooleDial extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'swoole:dial';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '呼叫队列';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        \Swoole\Runtime::enableCoroutine();
        \Swoole\Coroutine\run(function () {
            $pool = new \Swoole\Database\PDOPool((new \Swoole\Database\PDOConfig)
                ->withHost(config('database.connections.mysql.host'))
                ->withPort(config('database.connections.mysql.port'))
                // ->withUnixSocket('/tmp/mysql.sock')
                ->withDbName(config('database.connections.mysql.database'))
                ->withCharset(config('database.connections.mysql.charset'))
                ->withUsername(config('database.connections.mysql.username'))
                ->withPassword(config('database.connections.mysql.password'))
            );
            $key = config('freeswitch.redis_key.dial');
            Redis::del($key);
            while (true) {
                $uuid = Redis::lpop($key);
                if($uuid == null){
                    sleep(2);
                    continue;
                }
                //开户协程发起通话并监听
                \Swoole\Coroutine::create(function () use ($uuid,$pool){
                    //(new EslListen())->run($uuid);
                    $fs = new SwooleFreeswitch();
                    if (!$fs->connect()) {
                        Log::info("未连接上freeswitch:uuid=".$uuid);
                        return false;
                    }
                    $pdo = $pool->get();
                    $statement = $pdo->prepare('SELECT * FROM cdr WHERE uuid = ? limit 1');
                    if (!$statement) {
                        $pool->put($pdo);
                        return false;
                    }
                    $result = $statement->execute([$uuid]);
                    if (!$result) {
                        $pool->put($pdo);
                        return false;
                    }
                    $cdr = $statement->fetch();
                    if ($cdr === false){
                        $pool->put($pdo);
                        return false;
                    }
                    if (!$cdr['aleg_uuid'] || !$cdr['bleg_uuid']){
                        $pool->put($pdo);
                        return false;
                    }

                    $record_url = config('freeswitch.record_url');
                    $fs_dir = '/usr/local/freeswitch';

                    //是呼叫分机还是呼叫外线电话
                    $statement = $pdo->prepare('SELECT * FROM sip WHERE username = ? limit 1');
                    if (!$statement) {
                        $pool->put($pdo);
                        return false;
                    }
                    $result = $statement->execute([$cdr['callee']]);
                    if (!$result) {
                        $pool->put($pdo);
                        return false;
                    }
                    $sip = $statement->fetch();
                    if ($sip === false){
                        $statement = $pdo->prepare('SELECT * FROM gateway WHERE id = ? limit 1');
                        if (!$statement) {
                            $pool->put($pdo);
                            return false;
                        }
                        $result = $statement->execute([$cdr['gateway_id']]);
                        if (!$result) {
                            $pool->put($pdo);
                            return false;
                        }
                        $gateway = $statement->fetch();
                        if ($gateway === false){
                            Log::info(sprintf("呼叫B时网关ID：%d 不存在",$cdr->gateway_id));
                            $pool->put($pdo);
                            return false;
                        }
                        $outbound = $gateway['outbound_caller_id'] ? sprintf("{origination_caller_id_number=%s}{origination_caller_id_name=%s}",$gateway['outbound_caller_id'],$gateway['outbound_caller_id']) : null;
                        $originate = sprintf("originate {origination_uuid=%s}user/%s &bridge(%s{origination_uuid=%s}sofia/gateway/gw%d/%s%s)",
                            $cdr['aleg_uuid'],$cdr['caller'],$outbound,$cdr['bleg_uuid'],$gateway['id'],$gateway['prefix'],$cdr['callee']
                        );
                    }else{
                        $originate = sprintf("originate {origination_uuid=%s}user/%s &bridge({origination_uuid=%s}user/%s)",
                            $cdr['aleg_uuid'],$cdr['caller'],$cdr['bleg_uuid'],$cdr['callee']
                        );
                        $local_call = true;
                    }
                    $pool->put($pdo);

                    $fs->events("CHANNEL_ANSWER CHANNEL_HANGUP_COMPLETE");
                    $fs->filteruuid($cdr['aleg_uuid']);
                    $fs->filteruuid($cdr['bleg_uuid']);
                    $fs->bgapi($originate);
                    while (true) {
                        //录音目录
                        $filepath = $fs_dir . '/recordings/' . date('Y/m/d/');
                        $received_parameters = $fs->recvEvent();
                        if (!empty($received_parameters)) {
                            $json = $fs->serialize($received_parameters);
                            $curUuid = Arr::get($json, 'Unique-ID', null);
                            $eventname = Arr::get($json, 'Event-Name', null);
                            $otherUuid = Arr::get($json, 'Other-Leg-Unique-ID', null);
                            switch ($eventname) {
                                case 'CHANNEL_ANSWER':
                                    $pdo = $pool->get();
                                    //被叫应答后
                                    if ($otherUuid) {
                                        //开启全程录音
                                        $fullfile = $filepath . 'full_' . $cdr['uuid'] . '.wav';
                                        $fs->bgapi("uuid_record {$curUuid} start {$fullfile} 7200");
                                        $statement = $pdo->prepare('update cdr set answer_time = ?,record_file = ? where uuid = ?');
                                        $statement->execute([date('Y-m-d H:i:s'), str_replace($fs_dir, $record_url, $fullfile), $uuid]);
                                        if (isset($local_call)&&$local_call===true){
                                            $statement = $pdo->prepare('update sip set state = ? where username = ?');
                                            $statement->execute(['active', $cdr['callee']]);
                                        }
                                    }else{
                                        $statement = $pdo->prepare('update cdr set start_time = ? where uuid = ?');
                                        $statement->execute([date('Y-m-d H:i:s'), $uuid]);
                                        $statement = $pdo->prepare('update sip set state = ? where username = ?');
                                        $statement->execute(['active', $cdr['caller']]);
                                    }
                                    $pool->put($pdo);
                                    break;
                                case 'CHANNEL_HANGUP_COMPLETE':
                                    $pdo = $pool->get();
                                    $statement = $pdo->prepare('SELECT * FROM cdr WHERE uuid = ? limit 1');
                                    $result = $statement->execute([$uuid]);
                                    $cdr = $statement->fetch();
                                    if ($cdr !== false && $cdr['end_time'] == null) {
                                        $endTime = date('Y-m-d H:i:s');
                                        //A的挂断事件
                                        if ($curUuid == $cdr['aleg_uuid']) {
                                            $billsec = $cdr['answer_time'] ? strtotime($endTime) - strtotime($cdr['answer_time']) : 0;
                                        } else {
                                            $billsec = Arr::get($json, 'variable_billsec', 0);
                                        }
                                        $statement = $pdo->prepare('update cdr set end_time = ?,billsec = ? where uuid = ?');
                                        $statement->execute([$endTime, $billsec, $uuid]);
                                    }
                                    if (isset($local_call)&&$local_call===true){
                                        $statement = $pdo->prepare('update sip set state = ? where username in(?,?)');
                                        $statement->execute(['down', $cdr['caller'], $cdr['callee']]);
                                    }else{
                                        $statement = $pdo->prepare('update sip set state = ? where username = ?');
                                        $statement->execute(['down', $cdr['caller']]);
                                    }
                                    $pool->put($pdo);
                                    break 2;
                                default:
                                    break;
                            }
                        }
                    }
                    $fs->disconnect();
                });
            }
        });
    }
}
